namespace Pp.Repository
{
    using System;
    using System.Collections.Generic;
    using System.Configuration;
    using System.Data;
    using System.Drawing;
    using System.Drawing.Drawing2D;
    using System.Globalization;
    using System.IO;
    using System.Linq;
    using System.Net.Mail;
    using System.Reflection;
    using System.Threading;
    using System.Web;
    using System.Web.Mail;
    using Core;
    using Core.Extentions;
    using Core.File;
    using Core.FluentNH;
    using Domain.Model;
    using Dto;
    using Globalization;
    using NHibernate;
    using NHibernate.Criterion;
    using NHibernate.Transform;

    public class BaseRepository<T>
    {
        public ISession Session;
        public User CurrentUser;
        public HttpServerUtilityBase Server { get; set; }
        public BaseRepository(ISession session, HttpServerUtilityBase serverUtilityBase)
        {
            Session = session ?? LoadSession();
            BaseCriteria = Session.CreateCriteria(typeof(T));
            Session.BeginTransaction(IsolationLevel.ReadCommitted);
            Server = serverUtilityBase;
        }

        public ICriteria BaseCriteria;
        private static ISession LoadSession()
        {
            return ConfigurationItem.Instance.OpenSession();
        }
        public int TotalCount()
        {
            return Session.CreateCriteria(typeof(T)).SetProjection(Projections.Count("Id")).UniqueResult<int>();
        }
        public int TotalCount(ICriteria criteria)
        {
            return criteria.SetProjection(Projections.Count("Id")).UniqueResult<int>();
        }
        public bool IsExist(ICriteria criteria)
        {
            return criteria.SetProjection(Projections.Count("Id")).UniqueResult<int>() > 0;
        }
        public IList<T> GetAll()
        {
            return Session.CreateCriteria(typeof(T))
                .List<T>().ToList();
        }
        public PageList<T> GetAll(int? page, int maxResults, string urlPrefix)
        {
            var pagenumber = page.HasValue ? page.Value : 0;
            var pageCount = Session.CreateCriteria(typeof(T)).SetProjection(Projections.Count("Id")).UniqueResult<int>();
            var list = Session.CreateCriteria(typeof(T))
                .SetFirstResult(pagenumber * maxResults).SetMaxResults(maxResults)
                .AddOrder(Order.Desc("CreateDate"))
                .List<T>();
            return new PageList<T>
            {
                List = list,
                PageInfo = new PageInfo { ListCount = pageCount, UrlPrefix = urlPrefix, PageNumber = pagenumber, PageSize = maxResults }
            };
        }
        public PageList<T> GetAll(int? page, int maxResults, string urlPrefix, ICriterion criterion)
        {
            var pagenumber = page.HasValue ? page.Value : 0;
            var pageCount = TotalCount(Session.CreateCriteria(typeof(T)).Add(criterion));
            var list = Session.CreateCriteria(typeof(T))
                .SetFirstResult(pagenumber * maxResults).SetMaxResults(maxResults)
                .AddOrder(Order.Desc("CreateDate"))
                .Add(criterion)
                .List<T>();
            return new PageList<T>
            {
                List = list,
                PageInfo = new PageInfo { ListCount = pageCount, UrlPrefix = urlPrefix, PageNumber = pagenumber, PageSize = maxResults }
            };
        }
        public T Get(Guid? id)
        {
            return Session.CreateCriteria(typeof(T))
                .Add(Restrictions.Eq("Id", id))
                .UniqueResult<T>();
        }
        public PageList<TData> GetAll<TData>(int? page, int maxResults, string urlPrefix, ICriteria criteria)
        {
            var type = typeof(TData);
            var pagenumber = page.HasValue ? page.Value : 0;
            var pageCount = TotalCount(criteria);
            var list = criteria
                .SetFirstResult(pagenumber * maxResults).SetMaxResults(maxResults)
                .AddOrder(Order.Desc("CreateDate"));
            var pList = Projections.ProjectionList();
            foreach (var property in type.GetProperties()
                .Where(property => property.MemberType == MemberTypes.Property))
            {
                pList.Add(Projections.Property(property.Name), property.Name);
            }
            return new PageList<TData>
            {
                List = list.SetProjection(pList).SetResultTransformer(new AliasToBeanResultTransformer(type)).List<TData>().ToList(),
                PageInfo = new PageInfo { ListCount = pageCount, UrlPrefix = urlPrefix, PageNumber = pagenumber, PageSize = maxResults }
            };
        }
        public TData Get<TData>(Guid? id)
        {
            var type = typeof(TData);
            var a = Session.CreateCriteria(typeof(T))
                .Add(Restrictions.Eq("Id", id));
            var list = Projections.ProjectionList();
            foreach (var property in type.GetProperties()
                .Where(property => property.MemberType == MemberTypes.Property))
            {
                list.Add(Projections.Property(property.Name), property.Name);
            }
            a.SetProjection(list);
            return a.SetResultTransformer(new AliasToBeanResultTransformer(type)).UniqueResult<TData>();
        }

        public void Save(T entity)
        {
            Session.Save(entity);
            Session.Transaction.Commit();
            Session.BeginTransaction(IsolationLevel.ReadCommitted);
        }
        public void Update(T entity)
        {
            Session.Update(entity);
            Session.Transaction.Commit();
            Session.BeginTransaction(IsolationLevel.ReadCommitted);
        }
        public Result Delete(T gallery)
        {
            Session.Delete(gallery);
            Session.Transaction.Commit();
            Session.BeginTransaction(IsolationLevel.ReadCommitted);
            return Result.AsSuccess();
        }
        public void UploadImage(System.Web.HttpPostedFileBase postedFile, int templateWidth, int templateHeight, string fileSaveUrl)
        {
            Image initImage = Image.FromStream(postedFile.InputStream, true);
            if (initImage.Width <= templateWidth && initImage.Height <= templateHeight)
            {
                initImage.Save(fileSaveUrl, System.Drawing.Imaging.ImageFormat.Jpeg);
            }
            else
            {
                double templateRate = double.Parse(templateWidth.ToString(CultureInfo.InvariantCulture)) / templateHeight;
                double initRate = double.Parse(initImage.Width.ToString(CultureInfo.InvariantCulture)) / initImage.Height;
                if (templateRate == initRate)
                {

                    Image templateImage = new Bitmap(templateWidth, templateHeight);
                    Graphics templateG = Graphics.FromImage(templateImage);
                    templateG.InterpolationMode = InterpolationMode.High;
                    templateG.SmoothingMode = SmoothingMode.HighQuality;
                    templateG.Clear(Color.White);
                    templateG.DrawImage(initImage, new Rectangle(0, 0, templateWidth, templateHeight), new Rectangle(0, 0, initImage.Width, initImage.Height), System.Drawing.GraphicsUnit.Pixel);
                    templateImage.Save(fileSaveUrl, System.Drawing.Imaging.ImageFormat.Jpeg);
                }

                else
                {

                    Image pickedImage = null;
                    Graphics pickedG = null;


                    var fromR = new Rectangle(0, 0, 0, 0);
                    var toR = new Rectangle(0, 0, 0, 0);

                    if (templateRate > initRate)
                    {

                        pickedImage = new Bitmap(initImage.Width, int.Parse(Math.Floor(initImage.Width / templateRate).ToString(CultureInfo.InvariantCulture)));
                        pickedG = Graphics.FromImage(pickedImage);


                        fromR.X = 0;
                        fromR.Y = int.Parse(Math.Floor((initImage.Height - initImage.Width / templateRate) / 2).ToString(CultureInfo.InvariantCulture));
                        fromR.Width = initImage.Width;
                        fromR.Height = int.Parse(Math.Floor(initImage.Width / templateRate).ToString(CultureInfo.InvariantCulture));


                        toR.X = 0;
                        toR.Y = 0;
                        toR.Width = initImage.Width;
                        toR.Height = int.Parse(Math.Floor(initImage.Width / templateRate).ToString(CultureInfo.InvariantCulture));
                    }

                    else
                    {
                        pickedImage = new Bitmap(int.Parse(Math.Floor(initImage.Height * templateRate).ToString(CultureInfo.InvariantCulture)), initImage.Height);
                        pickedG = Graphics.FromImage(pickedImage);

                        fromR.X = int.Parse(Math.Floor((initImage.Width - initImage.Height * templateRate) / 2).ToString(CultureInfo.InvariantCulture));
                        fromR.Y = 0;
                        fromR.Width = int.Parse(Math.Floor(initImage.Height * templateRate).ToString(CultureInfo.InvariantCulture));
                        fromR.Height = initImage.Height;

                        toR.X = 0;
                        toR.Y = 0;
                        toR.Width = int.Parse(Math.Floor(initImage.Height * templateRate).ToString(CultureInfo.InvariantCulture));
                        toR.Height = initImage.Height;
                    }


                    pickedG.InterpolationMode = InterpolationMode.HighQualityBicubic;
                    pickedG.SmoothingMode = SmoothingMode.HighQuality;


                    pickedG.DrawImage(initImage, toR, fromR, GraphicsUnit.Pixel);


                    Image templateImage = new Bitmap(templateWidth, templateHeight);
                    Graphics templateG = Graphics.FromImage(templateImage);
                    templateG.InterpolationMode = InterpolationMode.High;
                    templateG.SmoothingMode = SmoothingMode.HighQuality;
                    templateG.Clear(Color.White);
                    templateG.DrawImage(pickedImage, new Rectangle(0, 0, templateWidth, templateHeight), new Rectangle(0, 0, pickedImage.Width, pickedImage.Height), GraphicsUnit.Pixel);
                    templateImage.Save(fileSaveUrl, System.Drawing.Imaging.ImageFormat.Jpeg);
                    templateG.Dispose();
                    templateImage.Dispose();
                    pickedG.Dispose();
                    pickedImage.Dispose();
                }
            }


            initImage.Dispose();
        }

        public Result<FileInfo> SavePicture(string linkRoot, HttpPostedFileBase fileItem, Size size, Guid? id)
        {
            try
            {
                var galleryRoot = Server.MapPath(linkRoot);
                var folderExists = Directory.Exists(galleryRoot);
                if (!folderExists)
                    Directory.CreateDirectory(galleryRoot);
                var fileId = id + (size.Width + "x" + size.Height) + ".jpg";
                var file = galleryRoot + "/" + fileId;
                if (File.Exists(file))
                    File.Delete(file);
                ThreadPool.QueueUserWorkItem(d => UploadImage(fileItem, size.Width, size.Height, file));
                return Result<FileInfo>.AsSuccess(new FileInfo(file));
            }
            catch (Exception ex)
            {
                return Result<FileInfo>.AsError(Res.Information_img_upload_error);
            }
        }
#pragma warning disable 612,618

        public Result<System.Net.Mail.MailMessage> CreateMail(string subject, MailType mailType, List<MailModel> mailModels, params string[] to)
        {
            if (mailModels == null) mailModels = new List<MailModel>();
            mailModels.Add(new MailModel("sitelink", "http://www.projenipaylas.com"));
            var file = new FileReader(Server.MapPath("/Content/MailTemplate/Default/{0}.html".FormatWith(mailType.ToString())));
            var myEmail = new System.Net.Mail.MailMessage { Body = file.GetMailTemplat(mailModels), Subject = subject };
            foreach (var s in to.Where(d => d.CheckMail()))
                myEmail.To.Add(s);

            return Result<System.Net.Mail.MailMessage>.AsSuccess(myEmail);
        }
        public Result SendMail(System.Net.Mail.MailMessage message)
        {
            if (message == null) throw new ArgumentNullException("message");
            try
            {
                var mail = ConfigurationManager.AppSettings.Get("MailAdress");
                var pass = ConfigurationManager.AppSettings.Get("Password");
                var hostIp = ConfigurationManager.AppSettings.Get("HostIp");
                var port = ConfigurationManager.AppSettings.Get("Port");
                var cred = new System.Net.NetworkCredential(mail, pass);
                message.From = new MailAddress(mail);
                message.IsBodyHtml = true;
                var smtp = new SmtpClient(hostIp, int.Parse(port))
                               {
                                   UseDefaultCredentials = false,
                                   EnableSsl = true,
                                   Credentials = cred
                               };

                ThreadPool.QueueUserWorkItem(d => smtp.Send(message));
                return Result.AsSuccess();
            }
            catch (Exception ex)
            {
                return Result.AsError(ex.Message);
            }
        }
#pragma warning restore 612,618
    }
}
